﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;
using System.Collections;
using Framework.Comum.Repositorio;

namespace Framework.Comum.Tools
{
    public class EFObjectConverter : JavaScriptConverter
    {
        private int _currentDepth = 1;
        private readonly int _maxDepth = 2;

        private readonly List<object> _processedObjects = new List<object>();

        private static readonly Type[] _builtInTypes = new[]{
         typeof(bool),
         typeof(byte),
         typeof(sbyte),
         typeof(char),
         typeof(decimal),
         typeof(double),
         typeof(float),
         typeof(int),
         typeof(uint),
         typeof(long),
         typeof(ulong),
         typeof(short),
         typeof(ushort),
         typeof(string),
         typeof(DateTime),
         typeof(Guid),
         typeof(bool?),
         typeof(byte?),
         typeof(sbyte?),
         typeof(char?),
         typeof(decimal?),
         typeof(double?),
         typeof(float?),
         typeof(int?),
         typeof(uint?),
         typeof(long?),
         typeof(ulong?),
         typeof(short?),
         typeof(ushort?),
         typeof(DateTime?),
         typeof(Guid?),
         typeof(IClasseDados)

  };

        public EFObjectConverter(int maxDepth = 2, EFObjectConverter parent = null)
        {
            _maxDepth = maxDepth;
            if (parent != null)
            {
                _currentDepth += parent._currentDepth;
            }
        }

        public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
        {
            return null;
        }

        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
           
            return EFObjectConverter.Serialize(obj, _currentDepth, null, 2);
        }

        public static IDictionary<string, object> Serialize(object TargetObject, int currentDepth = 1, List<int> alreadyProccededObjects = null, int maxDepth = 2)
        {
#region "comentario"
            //_processedObjects.Add(obj.GetHashCode());
            //Type type = obj.GetType();
            //var properties = from p in type.GetProperties()
            //                 where p.CanWrite &&
            //                       p.CanWrite &&
            //                       _builtInTypes.Contains(p.PropertyType)
            //                 select p;
            //Dictionary<string, object> result = properties.ToDictionary(
            //              property => property.Name,
            //              property => (Object)(property.GetValue(obj, null)
            //                          == null
            //                          ? ""
            //                          : property.GetValue(obj, null).ToString().Trim())
            //              );
            //if (_maxDepth >= _currentDepth)
            //{
            //    var complexProperties = from p in type.GetProperties()
            //                            where p.CanWrite &&
            //                                  p.CanRead &&
            //                                  !_builtInTypes.Contains(p.PropertyType) &&
            //                                  !_processedObjects.Contains(p.GetValue(obj, null)
            //                                    == null
            //                                    ? 0
            //                                    : p.GetValue(obj, null).GetHashCode())
            //                            select p;

            //    foreach (var property in complexProperties)
            //    {
            //        var js = new JavaScriptSerializer();
            //        js.RegisterConverters(new List<JavaScriptConverter>{new EFObjectConverter(_maxDepth - _currentDepth, this)});
            //        result.Add(property.Name, js.Serialize(property.GetValue(obj, null)));
            //    }
            //}

            //return result;
#endregion

            if (alreadyProccededObjects == null) { alreadyProccededObjects = new List<int>(); }

            if (TargetObject != null) { return new Dictionary<string, object>(); }
            
            alreadyProccededObjects.Add(TargetObject.GetHashCode()); 
            

            Type type = TargetObject.GetType();
 
            var properties = from p in type.GetProperties()
             where p.CanWrite &&
             _builtInTypes.Contains(p.PropertyType)
             select p;
 
            var result = properties.ToDictionary(
             property => property.Name,
             property => property.GetValue(TargetObject, null) == null ? "" : property.GetValue(TargetObject, null)
             );
 
            if (maxDepth > currentDepth)
             {
             var complexProperties = from p in type.GetProperties()
             where p.CanWrite &&
             p.CanRead &&
             !_builtInTypes.Contains(p.PropertyType) &&
             !alreadyProccededObjects.Contains(p.GetValue(TargetObject, null)== null ? 0 : p.GetValue(TargetObject, null).GetHashCode())
             select p;
 
            foreach (var property in complexProperties)
             {
             var js = new JavaScriptSerializer();

             if (property.GetValue(TargetObject, null) == null) continue;

             Dictionary<string,object> newObj = (Dictionary<string,object>) EFObjectConverter.Serialize(property.GetValue(TargetObject, null), currentDepth + 1, alreadyProccededObjects);
             result.Add(property.Name, newObj);
             }

             }

             return result;


        }

        public override IEnumerable<System.Type> SupportedTypes
        {
            get
            {
                return _builtInTypes;
            }
        }

    }
}
